/*
 * 在 Orchard 模块中创建 RESTful Web API 与创建 MVC 控制器非常相似，
 * 基本上与在纯 ASP.NET Core 中创建 API 相同（请参阅相关教程：
 * https://docs.microsoft.com/en-us/aspnet/core/web-api/）。让我们看一个基本示例！
 *
 * 请注意，开箱即用的 Orchard 也提供了 Web API：
 * 有许多 RESTful API 端点可用于内容和租户管理，
 * 以及许多模块贡献的 GraphQL API 基础设施（请参阅：
 * https://docs.orchardcore.net/en/latest/docs/reference/modules/Apis.GraphQL/），您也可以扩展它。
 */

using Ruitu.Edu.TrainingDemo.Permissions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using OrchardCore.ContentManagement;
using System.Threading.Tasks;

namespace Ruitu.Edu.TrainingDemo.Controllers;

/// <summary>
/// API 控制器 - 提供 RESTful Web API 端点
/// 
/// 主要用途：
/// - 为外部应用程序提供内容访问接口
/// - 演示如何在 Orchard Core 中创建 API 端点
/// - 展示权限验证和内容检索
/// 
/// 使用场景：
/// - 移动应用程序获取内容数据
/// - 单页应用程序 (SPA) 调用 API
/// - 第三方系统集成
/// 
/// 设计原因：
/// - 遵循 ASP.NET Core Web API 最佳实践
/// - 使用属性路由提供清晰的 API 路径
/// - 实现适当的授权和认证机制
/// 
/// 设计模式：
/// - RESTful API 设计模式
/// - 依赖注入模式：通过构造函数注入服务
/// - 授权模式：使用 IAuthorizationService 进行权限验证
/// </summary>
// 此控制器将为我们检索 Person Page 内容项作为简单示例，
// 尽管如此，它展示了您需要了解的最重要的事情。
// 如果您想看到更复杂的控制器示例，请查看官方源代码中 OrchardCore.Content 模块中的 ApiController。

// 使用属性路由为此控制器中的所有操作提供适当的路由。
[Route("api/Ruitu.Edu.TrainingDemo")]
// ApiController 属性不是严格必需的，但非常有用，请参阅：
// https://docs.microsoft.com/en-us/aspnet/core/web-api/#apicontroller-attribute
[ApiController]
// 我们将在操作（即 API 端点）中处理授权，因此这里不需要其他内容。
// 请注意，API 端点大多数时候应该使用 "Api" 认证方案：
// 这与标准用户通过 cookie 进行认证的方式不同。
[Authorize(AuthenticationSchemes = "Api"), IgnoreAntiforgeryToken, AllowAnonymous]
public sealed class ApiController : ControllerBase
{
    private readonly IAuthorizationService _authorizationService;
    private readonly IContentManager _contentManager;

    /// <summary>
    /// 构造函数 - 通过依赖注入初始化所需服务
    /// </summary>
    /// <param name="authorizationService">授权服务，用于权限验证</param>
    /// <param name="contentManager">内容管理器，用于内容操作</param>
    public ApiController(IAuthorizationService authorizationService, IContentManager contentManager)
    {
        _authorizationService = authorizationService;
        _contentManager = contentManager;
    }

    /// <summary>
    /// 获取内容项 - 根据内容项 ID 检索 Person Page 内容
    /// 
    /// 您可以查找之前创建的 Person Page 的 ID
    /// （当您从管理内容项列表中打开一个时，URL 将包含它作为 /Admin/Contents/ContentItems/<content item ID>），
    /// 并使用它通过 /api/Ruitu.Edu.TrainingDemo?contentItemId=<content item ID> 访问此操作。
    /// 请注意，您只能使用从 Orchard 管理界面设置的 OpenID 应用程序的客户端 ID 和密钥进行授权。
    /// 更多信息请参阅：https://docs.orchardcore.net/en/latest/docs/reference/modules/OpenId/。
    /// 如果您只想快速测试此 API，请删除上面的 Authorize 属性。
    /// </summary>
    /// <param name="contentItemId">要检索的内容项 ID</param>
    /// <returns>返回内容项的 JSON 表示，如果未找到则返回 NotFound</returns>
    [HttpGet]
    public async Task<IActionResult> Get(string contentItemId)
    {
        // 当然，授权在 API 端点中也很重要。我们在这里重用之前创建的权限。
        // 要对 API 进行身份验证，您可以使用任何 ASP.NET Core 认证方案，
        // 但 Orchard 提供各种基于 OpenID 的选项。
        // 如果您只想快速检查 API，请在管理界面中为匿名角色授予权限。
        if (!await _authorizationService.AuthorizeAsync(User, PersonPermissions.ManagePersons))
        {
            return this.ChallengeOrForbid("Api");
        }

        // 再次执行通常的操作。
        var contentItem = await _contentManager.GetAsync(contentItemId);

        // 只允许检索 Person Page 项目。
        if (contentItem?.ContentType != ContentTypes.PersonPage) contentItem = null;

        // 操作将自动返回内容项的 JSON 表示。然后您可以从 Web SPA 或移动应用程序中使用它，例如。
        return contentItem == null ? NotFound() : Ok(contentItem);
    }
}

// 训练部分结束：Web API

// 下一站：Middlewares/RequestLoggingMiddleware.cs
